#ifndef BASEDEVICE_H
#define BASEDEVICE_H

#include <QObject>
#include "Port/BasePort.h"
//#include "Command/BaseCmd.h"
#include "Function/BaseFunc.h"
#include "DataType/Package.h"
#include "CommandManage/CommandProcesser.h"
#include "CommandManage/CommandSender.h"
#include "Port/BasePort.h"
#include "DataType/PortStruct.h"
#include "Protocol/BaseProtocol.h"
//#include "Encrypt/SM4Encrypt.h"


class BaseDevice : public QObject
{
    Q_OBJECT

public:

    Q_INVOKABLE explicit BaseDevice(QObject *parent = 0) : QObject(parent)
    {

        cmdProcesser = new CommandProcesser(this);
        cmdSender = new CommandSender(this);
        connect(cmdSender,SIGNAL(postDataSignal(PortStruct,Package)),this,SIGNAL(postDataSignal(PortStruct,Package)));
        connect(cmdSender,SIGNAL(sendDataSignal(PortStruct,QByteArray)),this,SIGNAL(sendDataSignal(PortStruct,QByteArray)));
        connect(cmdSender,SIGNAL(httpGetDataSignal(PortStruct,Package)),this,SIGNAL(httpGetDataSignal(PortStruct,Package)));
        connect(cmdSender,SIGNAL(cmdTimeoutSignal(PortStruct,QSharedPointer<BaseCmd>)),this,SLOT(cmdTimeoutSlot(PortStruct,QSharedPointer<BaseCmd>)));
       //  connect(SM4Encrypt::getInstance(),SIGNAL(sm4InitComlete()),this,SLOT(onReceiveSM4InitComplete()));
    }
    virtual ~BaseDevice(){}

    QString name() const
    {
        return this->objectName();
    }

    void setName(const QString &name)
    {
        this->setObjectName(name);
    }

    void bindingPort(BasePort *port)
    {
 //       qDebug()<<"Connect CMD SLOT NOW------------------------";
        m_portList.append(port);
        connect(this,SIGNAL(postDataSignal(PortStruct,Package)),port,SLOT(postDataSlot(PortStruct,Package)));
        connect(port, SIGNAL(receiveDataSignal(PortStruct,QByteArray)), this, SLOT(receiveDataSlot(PortStruct,QByteArray)));
        connect(this,SIGNAL(sendDataSignal(PortStruct,QByteArray)),port,SLOT(sendDataSlot(PortStruct,QByteArray)));
        connect(port, SIGNAL(clientDisconnectedSignal(PortStruct)), this, SLOT(clientDisconnectedSlot(PortStruct)));
        connect(port, SIGNAL(isConnectedSignal(bool,PortStruct)), this, SLOT(isConnectedSlot(bool,PortStruct)));
        connect(this, SIGNAL(openPortSignal(PortStruct)), port, SLOT(openSlot(PortStruct)));
        connect(this, SIGNAL(closePortSignal(PortStruct)), port, SLOT(closeSlot(PortStruct)));
        connect(this,SIGNAL(httpGetDataSignal(PortStruct,Package)),port,SLOT(httpGetDataSlot(PortStruct,Package)));
    }



protected:

    CommandProcesser *cmdProcesser;
    CommandSender *cmdSender;
    QList<BasePort*> m_portList;


    void setIsEncrypt(bool isEncrypt)
    {
        cmdSender->setIsEncrypt(isEncrypt);
    }


    void setIsDecrypt(bool isDecrypt)
    {
        cmdProcesser->setIsDecrypt(isDecrypt);
    }


    virtual void cmdHandle(PortStruct source, QSharedPointer<BaseCmd> sharedCmd)
    {
        Q_UNUSED(source);
        Q_UNUSED(sharedCmd);
    }

    virtual void cmdTimeoutHandle(PortStruct target, QSharedPointer<BaseCmd> sharedCmd)
    {
        Q_UNUSED(target);
        Q_UNUSED(sharedCmd);
    }

    virtual void funcHandle(QSharedPointer<BaseFunc> sharedFunc)
    {
        Q_UNUSED(sharedFunc);
    }


    void registerProtocol(BaseProtocol* protocol)
    {
        cmdProcesser->registerProtocol(protocol);
        cmdSender->registerProtocol(protocol);
    }


    void sendCmd(PortStruct target,QSharedPointer<BaseCmd> sharedCmd)
    {
        cmdSender->sendCmd(target,sharedCmd);
    }

    void sendHttp(QByteArray jsonData)
    {
        //cmdSender->postHttpRequest(jsonData);
    }

    void sendHttpFile(QString mac,QString filename)
    {
        cmdSender->postHttpFileRequest(mac,filename);
    }

    void loginHttp(QString usr,QString pwd)
    {
        cmdSender->postHttpLogin(usr,pwd);
    }

    void sendHttpIdentifi(QByteArray jsonData)
    {
      //  cmdSender->postHttpIdentifi(jsonData);
    }

    void sendHttpResult(QByteArray jsonData)
    {
      //  cmdSender->postHttpResult(jsonData);
    }

    void sendHttpCreate(QByteArray jsonData)
    {
      //  cmdSender->postHttpCreate(jsonData);
    }



signals:
     void postDataSignal(PortStruct target,Package package);
    void sendDataSignal(PortStruct target,QByteArray data);
    void httpGetDataSignal(PortStruct target,Package package);
    void transferFuncSignal(QSharedPointer<BaseFunc> sharedFunc);
    void openPortSignal(PortStruct port);
    void closePortSignal(PortStruct port);


public slots:

    void onReceiveSM4InitComplete()
    {
        qDebug()<<"now going to onReceiveSM4InitComplete---------------------";
    }
    void receiveDataSlot(PortStruct source,QByteArray data)
    {
        qDebug()<<"now going to receiveDataSlot---------------------";

        qDebug()<<DataTypeConver::formatString(data.data());

        QList<QSharedPointer<BaseCmd> > cmdList = cmdProcesser->receiveData(data);
        for(int i=0; i<cmdList.size(); i++)
        {
            QSharedPointer<BaseCmd> sharedCmd = cmdList.at(i);
            if(!sharedCmd.isNull())
            {
                cmdSender->cancelResend(sharedCmd->cmdId());
                cmdHandle(source,sharedCmd);
            //    qDebug()<<"BaseDevic-sharedCmd isNull-";
            }
        }
    }

    void transferFuncSlot(QSharedPointer<BaseFunc> sharedFunc)
    {
        funcHandle(sharedFunc);
    }
    void cmdTimeoutSlot(PortStruct target, QSharedPointer<BaseCmd> sharedCmd)
    {
        cmdTimeoutHandle(target,sharedCmd);
    }


    virtual void isConnectedSlot(bool isConnect,PortStruct target)
    {
        Q_UNUSED(isConnect);
        Q_UNUSED(target);
    }

    virtual void clientDisconnectedSlot(PortStruct source)
    {
        Q_UNUSED(source);
    }

};

template <typename T>

class BaseInterface : public BaseDevice
{

public:

    explicit BaseInterface(QObject *parent = 0):BaseDevice(parent){}


protected:

    T* m_pInstance;

    typedef void (T:: *CmdHandlePointer)(PortStruct,QSharedPointer<BaseCmd>);
    QMap<int, CmdHandlePointer> m_cmdHandleMap;

    typedef void (T:: *FuncHandlePointer)(QSharedPointer<BaseFunc>);
    QMap<int, FuncHandlePointer> m_funcHandleMap;

    QMap<int, CmdHandlePointer> m_cmdTimeoutHandleMap;   

     void registerProtocol(BaseProtocol* protocol)
     {
         cmdProcesser->registerProtocol(protocol);
         cmdSender->registerProtocol(protocol);
     }

     void cmdHandle(PortStruct source,QSharedPointer<BaseCmd> sharedCmd)
     {
         int functionCode = sharedCmd->functionCode();
         CmdHandlePointer pHandle = m_cmdHandleMap.value(functionCode,NULL);
  //       qDebug()<<"pHandle is null?now functionCode ="<<functionCode;
         if(pHandle != NULL)
         {
 //            qDebug()<<"pHandle is not null";
             (m_pInstance->*pHandle)(source,sharedCmd);
         }
     }

     void cmdTimeoutHandle(PortStruct target,QSharedPointer<BaseCmd> sharedCmd)
     {
         int functionCode = sharedCmd->functionCode();
         CmdHandlePointer pHandle =


                 m_cmdTimeoutHandleMap.value(functionCode,NULL);
         if(pHandle != NULL)
         {
             (m_pInstance->*pHandle)(target,sharedCmd);
         }
     }

     void funcHandle(QSharedPointer<BaseFunc> sharedFunc)
     {
         int functionCode = sharedFunc->functionCode();
        // qDebug()<<"functionCode="<<functionCode;
         FuncHandlePointer pHandle = m_funcHandleMap.value(functionCode,NULL);
         if(pHandle != NULL)
         {
             (m_pInstance->*pHandle)(sharedFunc);
         }
     }



     void registerCmdHandler(int functionCode, QMetaObject cmdMetaObject,CmdHandlePointer pHandle)
     {
 //        qDebug()<<"registerCmd="<<functionCode;
         cmdProcesser->registerCmd(functionCode,cmdMetaObject);

         m_cmdHandleMap.insert(functionCode,pHandle);
     }

     void registerFuncHandler(int functionCode, FuncHandlePointer pHandle)
     {
         m_funcHandleMap.insert(functionCode,pHandle);
     }

     void registerCmdTimeOUTHandler(int functionCode, CmdHandlePointer pHandle)
     {
         m_cmdTimeoutHandleMap.insert(functionCode,pHandle);
     }


};



#endif // BASICDEVICE_H
